package com.SouthernWall_404.Age_Capitalism.common.World.Entity;

import com.SouthernWall_404.Age_Capitalism.AgeCapitalism;
import com.SouthernWall_404.Age_Capitalism.common.API.Info.StoreKeyInfo;
import com.SouthernWall_404.Age_Capitalism.common.Gui.Menu.ModMerchantMenu;
import com.SouthernWall_404.Age_Capitalism.common.Gui.Menu.ModSettingMerchantMenu;
import com.SouthernWall_404.Age_Capitalism.common.Init.ModBlockEntities;
import com.SouthernWall_404.Age_Capitalism.common.Network.ModChannels;
import com.SouthernWall_404.Age_Capitalism.common.Network.S2C.MerchantServerPacket;
import com.SouthernWall_404.Age_Capitalism.common.Network.S2C.StoreBlockEntityPacket;
import com.SouthernWall_404.Age_Capitalism.common.World.Items.StoreKeyItem;
import com.SouthernWall_404.Age_Capitalism.common.World.Items.StoreTagItem;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.trading.Merchant;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.apache.logging.log4j.LogManager;
import org.jetbrains.annotations.Nullable;

import java.util.OptionalInt;
import java.util.UUID;

public class StoreBlockEntity extends ChestBlockEntity implements MenuProvider, Merchant {

    private static String STOREPACK_TAG="store";
    private static String STOREPACK_KEY_TAG ="key";
    private static String STOREPACK_OFFERS_TAG ="offers";
    private static String STOREPACK_OFFERS_AMOUNT_TAG ="offers_amount";

    public MerchantOffers offers = new MerchantOffers();
    public Player tradingPlayer;
    public int selectedOffer=0;
    public String uuid=" ";
    public boolean highlighted=false;
//    public int merchantLevel = 1; // 职业等级


   public StoreBlockEntity(BlockPos blockPos, BlockState blockState) {

       this(ModBlockEntities.STORE_BLOCK_ENTITY.get(),blockPos,blockState);
    }


    public StoreBlockEntity(BlockEntityType<?> blockEntityType,BlockPos pos, BlockState state) {
        super(blockEntityType,pos, state);
        this.init();
    }
    public void setHighlighted(boolean highlight) {
        this.highlighted = highlight;
        setChanged(); // 标记需要更新
    }

    public boolean isHighlighted() {

        return highlighted;
    }

    public CompoundTag getKey()
    {
        UUID uuid=UUID.randomUUID();
        BlockPos blockPos=this.getBlockPos();
        Block block=this.getBlockState().getBlock();

        this.uuid=uuid.toString();

        CompoundTag keyPack=new CompoundTag();

        keyPack.putString("uuid",this.uuid);
        keyPack.putInt("x",blockPos.getX());
        keyPack.putInt("y",blockPos.getY());
        keyPack.putInt("z",blockPos.getZ());
        keyPack.putString("block",block.getName().getString());

        return keyPack;

    }
    /*
    用于打开交易界面
     */
    public void startTrading(Player player) {
        this.setTradingPlayer(player);
//        this.openTradingScreen(player, this.getDisplayName(), 1);

        OptionalInt $$3 = player.openMenu(
                new SimpleMenuProvider(
                        (p_45298_, p_45299_, p_45300_) ->
                                new ModMerchantMenu(p_45298_, p_45299_, this){

                                },
                        this.getDisplayName()
                ));
        if ($$3.isPresent()) {
            MerchantOffers $$4 = this.getOffers();
            if (!$$4.isEmpty()) {

                if(player instanceof ServerPlayer serverPlayer)
                {
                    ModChannels.sendToClient(new StoreBlockEntityPacket(this,$$3.getAsInt()),serverPlayer);
                }

                ModChannels.sendToClient(new MerchantServerPacket($$3.getAsInt(), $$4, 1, this.getVillagerXp(), this.showProgressBar(), this.canRestock()),player);
//                player.sendMerchantOffers($$3.getAsInt(), $$4, 1, this.getVillagerXp(), this.showProgressBar(), this.canRestock());
            }
        }

    }


    public void startSettingTrading(Player player) {
        this.setTradingPlayer(player);
//        this.openTradingScreen(player, this.getDisplayName(), 1);

        if(player instanceof ServerPlayer serverPlayer)
        {
            OptionalInt $$3 = player.openMenu(
                    new SimpleMenuProvider(
                            (p_45298_, p_45299_, p_45300_) ->
                                    new ModSettingMerchantMenu(p_45298_, p_45299_, this){

                                    },
                            this.getDisplayName()
                    ));
            if ($$3.isPresent()) {
                MerchantOffers $$4 = this.getOffers();
                ModChannels.sendToClient(new StoreBlockEntityPacket(this,$$3.getAsInt()),serverPlayer);
                ModChannels.sendToClient(new MerchantServerPacket($$3.getAsInt(), $$4, 1, this.getVillagerXp(), this.showProgressBar(), this.canRestock()),player);
//                player.sendMerchantOffers($$3.getAsInt(), $$4, 1, this.getVillagerXp(), this.showProgressBar(), this.canRestock());
            }
        }
    }
    //准备写数据持久化
    @Override
    protected void saveAdditional(CompoundTag tag) {
        super.saveAdditional(tag);

        CompoundTag modPack=new CompoundTag();
        CompoundTag storePack=new CompoundTag();

        storePack.putString(STOREPACK_KEY_TAG,this.uuid);


        CompoundTag root = new CompoundTag();
        ListTag offersList = new ListTag();

        for (MerchantOffer offer : offers) {
            if (offer != null) {
                // 序列化单个交易项
                CompoundTag offerTag = offer.createTag();
                offersList.add(offerTag);
            }
        }

        storePack.put(STOREPACK_OFFERS_TAG, offersList);
        storePack.putInt(STOREPACK_OFFERS_AMOUNT_TAG, offers.size());


        modPack.put(STOREPACK_TAG,storePack);

        tag.put(AgeCapitalism.MODID,modPack);
    }

    @Override
    public void load(CompoundTag nbt) {
        super.load(nbt);
        if (getType() == BlockEntityType.CHEST) {
            // 尝试升级为自定义类型
            getType();
        }
        if(nbt.contains(AgeCapitalism.MODID))
        {
            CompoundTag modPack=nbt.getCompound(AgeCapitalism.MODID);
            if(modPack.contains(STOREPACK_TAG))
            {
                CompoundTag storePack=modPack.getCompound(STOREPACK_TAG);
                if(storePack.contains(STOREPACK_KEY_TAG))
                {

                    this.uuid=storePack.getString(STOREPACK_KEY_TAG);
                }

                if(storePack.contains(STOREPACK_OFFERS_TAG)&&storePack.contains(STOREPACK_OFFERS_AMOUNT_TAG))
                {
                    int offer_amount=storePack.getInt(STOREPACK_OFFERS_AMOUNT_TAG);
                    ListTag offersList=storePack.getList(STOREPACK_OFFERS_TAG,CompoundTag.TAG_COMPOUND);

                    for (int i = 0; i < offersList.size(); i++) {
                        CompoundTag offerTag = offersList.getCompound(i);
                        try {
                            // 反序列化单个交易项
                            MerchantOffer offer = new MerchantOffer(offerTag);
                            offers.add(offer);
                        } catch (Exception e) {
                            // 处理损坏的交易项
                            LogManager.getLogger().error("Failed to load trade offer at index {}", i, e);
                        }
                    }
                }
            }
        }
    }
    @Override
    public void setChanged() {
        super.setChanged();
        if (this.level != null && !this.level.isClientSide) {
            this.syncToClient();
        }
    }

    public void syncToClient() {
        BlockState state = getBlockState();
        level.sendBlockUpdated(worldPosition, state, state, 3);
    }
    public void init()
    {

    }
    @Override
    public @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {

       ItemStack itemInHand=player.getItemInHand(InteractionHand.MAIN_HAND);
       Item item=itemInHand.getItem();
        if ((item instanceof StoreKeyItem storeKeyItem)&&!(item instanceof StoreTagItem))
       {
           String keyId=StoreKeyInfo.getFromItem(itemInHand).uuid.toString();
           if(keyId.equals(this.uuid))
           {
               return ChestMenu.threeRows(i,inventory,this);
           }
           else
           {
               player.displayClientMessage(Component.translatable("钥匙不匹配!"),true);
               return null;
           }
       }
        if(item instanceof StoreTagItem)
        {
            return new ModSettingMerchantMenu(i,inventory,this);
        }
        else
        {
            return null;
        }
    }




    @Override
    public ClientboundBlockEntityDataPacket getUpdatePacket() {
        return ClientboundBlockEntityDataPacket.create(this);
    }

    // 处理更新包
    @Override
    public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) {
        load(pkt.getTag());
    }

    // 获取更新标签
    @Override
    public CompoundTag getUpdateTag() {
        CompoundTag tag = super.getUpdateTag();
        saveAdditional(tag);
        return tag;
    }
    @Override
    public Component getDisplayName()
    {
        return Component.translatable(AgeCapitalism.MODID+".container.store");
    }


    @Override
    public void setTradingPlayer(@Nullable Player player) {
        this.tradingPlayer = player;

    }

    @Override
    public @Nullable Player getTradingPlayer() {
        return tradingPlayer;
    }

    @Override
    public MerchantOffers getOffers() {
        this.sellcheck();
        return offers;
    }

    @Override
    public void overrideOffers(MerchantOffers offers) {
        this.offers = offers;

        this.setChanged();
        this.getUpdateTag();


    }

    @Override
    public void notifyTrade(MerchantOffer p_45305_) {
        this.sellcheck();
       return;
    }

    @Override
    public void notifyTradeUpdated(ItemStack p_45308_) {
        this.sellcheck();

    }

    public NonNullList<ItemStack> getContainer()
    {
        return this.getItems();
    }

    public void setContainer(NonNullList<ItemStack> items)
    {
        this.setItems(items);
        this.setChanged();
    }

    public void sellcheck()
    {
        for(int i=0;i<this.offers.size();i++)//对于每种交易
        {
            sellCheckOffer(i);
        }
    }

    public boolean sellCheckOffer(int i)
    {
        MerchantOffer offer=offers.get(i);

        return sellCheckOffer(offer);
    }

    public boolean sellCheckOffer(MerchantOffer offer)
    {
        NonNullList<ItemStack> items=this.getItems();

        ItemStack itemForSell=offer.getResult();
        ItemStack itemForCostA=offer.getCostA();
        ItemStack itemForCostB=offer.getCostB();
        int goodAmount=0;
        boolean hasGood=false;//判断是否有货
        boolean hasASpace=false;//判断A是否有空间
        boolean hasBSpace=false;//判断B是否有空间

        int costASpaceAmount=0;
        int costBSpaceAmount=0;

        for(int j=0;j<items.size();j++)//遍历箱子内容物
        {
            ItemStack itemStack=items.get(j);
            if (ItemStack.isSameItemSameTags(itemStack,itemForSell))//如果有待售卖物品且数量足够
            {
                goodAmount+=itemStack.getCount();
                if(goodAmount>=itemForSell.getCount())
                {
                    hasGood=true;//设定有货
                }

            }

            if(itemStack.isEmpty())//如有空位
            {
                if(!hasASpace)//如果A的空间需求尚未满足
                {
                    costASpaceAmount+=itemForCostA.getMaxStackSize();//增加一组的空间
                }
                else if (!hasBSpace)//满足了，B还缺，填B
                {
                    costBSpaceAmount+=itemForCostB.getMaxStackSize();
                }
            }
            else if(ItemStack.isSameItemSameTags(itemStack,itemForCostB)//若是B
                    &&itemStack.getCount()<itemForCostB.getMaxStackSize())//并且未满
            {
                if(!hasBSpace)
                {
                    int space=itemForCostB.getMaxStackSize()-itemStack.getCount();
                    costBSpaceAmount+=space;
                }

            }
            else if (ItemStack.isSameItemSameTags(itemStack,itemForCostA)//若是A
                    &&itemStack.getCount()<itemForCostA.getMaxStackSize())//并且未满
            {
                if(!hasASpace)
                {
                    int space=itemForCostA.getMaxStackSize()-itemStack.getCount();
                    costASpaceAmount+=space;
                }
            }
            //该格子叠加完成，开始判定
            if(costASpaceAmount>=itemForCostA.getCount())//A空间足够，判定A够
            {
                hasASpace=true;
            }
            if(costBSpaceAmount>=itemForCostB.getCount())
            {
                hasBSpace=true;
            }
        }

        if(hasGood&&hasASpace&&hasBSpace)
        {
            offer.resetUses();
            return true;

        }
        else
        {
            offer.setToOutOfStock();
            return false;
        }
    }

    @Override
    public int getVillagerXp() {
        return 0;
    }

    @Override
    public void overrideXp(int p_45309_) {

    }

    @Override
    public boolean showProgressBar() {
        return false;
    }

    @Override
    public SoundEvent getNotifyTradeSound() {
        return null;
    }

    @Override
    public boolean isClientSide() {
        return this.getLevel().isClientSide;
    }
}
